package iit.projects.etaxi.model.service;

import java.text.MessageFormat;

import iit.projects.etaxi.model.dao.SequenceDao;
import iit.projects.etaxi.model.entity.Sequence;
import iit.projects.etaxi.model.exception.DuplicateSequenceException;
import iit.projects.etaxi.model.exception.SequenceNotFoundException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Transactional(readOnly=true)
public class SequenceGeneratorImpl implements SequenceGenerator {

	final Logger log = LoggerFactory.getLogger(SequenceGeneratorImpl.class);
	
	private static final int DEFAULT_ID_LENGTH = 5;
	private static final char DEFAULT_INJECT_CHARACTER = '0';
	
	private SequenceDao sequenceDao;
	
	@Override
	@Transactional(readOnly=false, propagation=Propagation.REQUIRED, rollbackFor=DuplicateSequenceException.class)
	public String getGeneratedCode(String sequenceName) throws DuplicateSequenceException {
		
		try {
			Sequence sequence = sequenceDao.findByPrimaryKey(sequenceName);
			sequence.setCurrval(sequence.getCurrval() + sequence.getIncrement());
			Sequence updatedSequence = sequenceDao.updateSequence(sequence);
			
			String id = generateId(updatedSequence.getPrefix(), updatedSequence.getIdLength(), 
								   updatedSequence.getInjectCharacter(), updatedSequence.getCurrval());
			
			return id;
		} catch (SequenceNotFoundException e) {
			if(log.isDebugEnabled()){
				log.debug("No Sequence found for name " + sequenceName);
			}
		}
		
		Sequence sequence = new Sequence();
		sequence.setSeqName(sequenceName);
		sequence.setIdLength(DEFAULT_ID_LENGTH);
		sequence.setInjectCharacter(DEFAULT_INJECT_CHARACTER);
		sequence.setIncrement(1);
		sequence.setCurrval(new Long(1));
		
		try {
			Sequence savedSequence = sequenceDao.addSequence(sequence);
			String id = generateId(savedSequence.getPrefix(), savedSequence.getIdLength(), 
								   savedSequence.getInjectCharacter(), savedSequence.getCurrval());

			return id;
		} catch (DuplicateSequenceException e) {
			log.error("Duplication Sequence for " + sequenceName);
			throw e;
		}
	}
	
	private String generateId(String prefix, int idLength, char injectChar,Long currVal){
		
		StringBuilder pattern = new StringBuilder(injectChar);
		int limit = (prefix != null)?prefix.length() : 0;

		for(int i = pattern.length(); i < (idLength - limit); i++){
			pattern.append(injectChar);
		}

		MessageFormat mf = new MessageFormat("{0,number,"+ pattern + "}");
		Object[] objs = {new Long(currVal)};
		String result = mf.format(objs);

		if(prefix != null){
			result = prefix + result;
		}
		return result;
	}

	public void setSequenceDao(SequenceDao sequenceDao) {
		this.sequenceDao = sequenceDao;
	}

}
